import datetime
import jwt

from common.response import Response
from config import BasicConfig
from constants.header_constant import UserHeaderConstant
from dao.user_dao import UserDAO
from models.user_model import UserModel
from schemas.user_schema import UserSchema, UserDeleteSchema, UserLoginSchema

BLACKLIST = set()


class UserService:

    def __init__(self):
        self.user_dao = UserDAO()

    async def create_user(self, params: UserSchema) -> Response:
        exists = await self.user_dao.get_by_query({'username': params.username})
        if exists:
            return Response.fail(f'已经有同名用户存在')
        await self.user_dao.insert_one(UserModel(**params.dict()))
        return Response.success()

    async def list_users(self, query_params: dict) -> Response:
        header = UserHeaderConstant.user_header
        data = await self.user_dao.get_users_by_query(query_params)
        res = {
            'header': header,
            'data': data,
        }
        return Response.success(res)

    async def delete_user(self, params: UserDeleteSchema) -> Response:
        _id = params.id
        await self.user_dao.delete_by_id(_id)
        return Response.success()

    async def login(self, params: UserLoginSchema) -> Response:
        """
        jwt生成一个包含用户身份信息和权限的令牌。这些令牌可以在客户端和服务器之间进行传递，以验证用户身份。
        jwt三个部分组成:header,payloads,signature.结构:header.payload.signature
        """
        exist = await self.user_dao.get_one_by_query({'username': params.username})
        if not exist:
            return Response.fail('用户不存在')
        if params.pwd != exist.pwd:
            return Response.fail('密码错误')
        # 身份验证和信息传递使用 JWT;只是需要一个唯一标识符，则使用 UUID

        token = generate_jwt_token(params.username)
        res = {
            'token': token
        }
        return Response.success(res)


def generate_jwt_token(username):
    # 过期时间设置为 1 小时
    expiration = datetime.datetime.now() + datetime.timedelta(hours=1)
    payload = {"username": username, "exp": expiration}
    token = jwt.encode(payload, BasicConfig.SECRET_KEY, algorithm="HS256")
    return token
